package us.kg.kotoriforest.schedule.util;

import com.alibaba.druid.pool.DruidDataSourceFactory;

import javax.sql.DataSource;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties;

/**
 * ClassName: us.kg.kotoriforest.schedule.util.JDBCUtil </br>
 * Description: 工具类 封装了连接池相关代码 可以从线程池中获取连接和归还连接 </br>
 * <strong>完成了 {@code JDBC} 中的加载驱动、获取链接、归还链接的部分</strong> </br>
 * 注：归还连接一定要使用工具类中的 {@code closeConnection} 方法
 *
 * @author Kotori rotroutine@163.com
 * @since 2024/12/1
 */
public final class JDBCUtil {
    // 数据库连接池 以接口作为类型 方便后期更换数据库连接池厂商
    private static final DataSource DATA_SOURCE;
    // TreadLocal 类保证了一个线程在其生命周期中只会使用同一个 Connection 对象 可以实现事务和提高连接池效率
    private static final ThreadLocal<Connection> THREAD_LOCAL = new ThreadLocal<>();

    static {
        Properties properties = new Properties();
        try (InputStream resourceAsStream = JDBCUtil.class.getClassLoader().getResourceAsStream("jdbc.properties")) {
            properties.load(resourceAsStream);
            DATA_SOURCE = DruidDataSourceFactory.createDataSource(properties);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 私有化构造函数，避免被实例化
     */
    private JDBCUtil() {
    }

    /**
     * 从连接池中获取连接 同一个线程取得的 {@code Connection} 对象有且只有一个
     *
     * @return 获取到的连接 如果没获取到会抛出异常
     * @throws RuntimeException 如果没有获取到连接会抛出此异常
     */
    public static Connection getConnection() {
        Connection connection = THREAD_LOCAL.get();
        if (null == connection) {
            try {
                connection = DATA_SOURCE.getConnection();
                THREAD_LOCAL.set(connection);
            } catch (SQLException e) {
                throw new RuntimeException(e);
            }
        }

        return connection;
    }

    /**
     * 归还连接 归还连接一定要通过该方法 不能自行调用 Connection 的 close 方法
     *
     * @throws RuntimeException 如果连接归还失败会抛出此异常
     */
    public static void closeConnection() {
        Connection connection = THREAD_LOCAL.get();
        if (null != connection) {
            try {
                connection.setAutoCommit(true); // 关闭事务
                connection.close();
                THREAD_LOCAL.remove();
            } catch (SQLException e) {
                throw new RuntimeException(e);
            }
        }
    }
}
